<template>
  <el-row>
    <el-col :span="5">
      <div class="h-full flex flex-col justify-between items-center">
        <div class="add-category">
          <el-tabs v-model="fileType" @tab-click="handleClick">
            <el-tab-pane :label="item.name" :name="item.type" v-for="item in parentData" :key="item.type">
              <el-tree :data="dataSource"
                       :props="defaultProps"
                       node-key="id"
                       highlight-current
                       default-expand-all
                       :current-node-key="0"
                       :expand-on-click-node="false"
                       @node-click="handleClickNode">
                <!-- 使用 scoped slot 来自定义 label -->
                <template #default="{ node, data }">
                  <span class="custom-tree-node">
                    <span class="flex items-center">
                      <el-icon size="20" class="mr-2.5">
                        <myIconFolder/>
                      </el-icon>
                      <el-text>{{ node.label }}</el-text>
                    </span>
                    <el-dropdown>
                      <span>
                        <el-icon>
                          <MoreFilled/>
                        </el-icon>
                      </span>
                      <template #dropdown>
                        <el-dropdown-menu v-if="data.cate_name !== '全部'">
                          <el-dropdown-item @click="addCategory(true, data)">新增分类</el-dropdown-item>
                          <el-dropdown-item @click="addCategory(false, data)">编辑分类</el-dropdown-item>
                          <el-dropdown-item @click="remove(data)">删除</el-dropdown-item>
                        </el-dropdown-menu>
                      </template>
                    </el-dropdown>
                  </span>
                </template>
              </el-tree>
            </el-tab-pane>
          </el-tabs>
        </div>
        <div class="flex items-center justify-center pa-5">
          <el-button type="primary" round plain :icon="CirclePlus" @click="addCategory(true)">新增分类</el-button>
        </div>
      </div>
    </el-col>
    <el-col :span="19">
      <div class="toolbar">
        <el-row :gutter="10" justify="space-between" align="middle">
          <el-col :span="12">
            <el-space alignment="center">
              <el-button v-if="props.dialog" type="primary" :disabled="!selectedItems.length" @click="handleUseImage">
                使用选中图片
              </el-button>
              <el-upload
                  :action="UploadUrl"
                  :headers="header"
                  :show-file-list="false"
                  :before-upload="beforeUpload"
                  :on-success="handleSuccess"
                  :on-error="handleError"
                  :data="uploadData"
                  name="files[]"
                  ref="upload"
                  multiple
                  v-model:file-list="fileList"
              >
                <el-button type="primary">点击上传</el-button>
              </el-upload>
              <el-button type="danger" :disabled="!selectedItems.length" @click="handleDelImage(false)">删除图片
              </el-button>
              <el-button :disabled="!selectedItems.length" @click="dialogCidVisible = true">移动</el-button>
            </el-space>
          </el-col>

          <el-col :span="12">
            <el-row :gutter="10" align="middle">
              <el-col :span="16">
                <el-input v-model="search.stored_name" style="width: 200px; margin-right: 10px;" clearable
                          placeholder="请输入图片名称">
                  <template #append>
                    <el-button :icon="Search" @click="getFileList()"/>
                  </template>
                </el-input>
              </el-col>
              <el-col :span="8">
                <div class="flex items-center">
                  <el-radio-group v-model="viewType" @change="handleChangeView">
                    <el-radio-button value="table">
                      <template #default>
                        <el-icon>
                          <myIconList/>
                        </el-icon>
                      </template>
                    </el-radio-button>
                    <el-radio-button value="grid">
                      <template #default>
                        <el-icon>
                          <Grid/>
                        </el-icon>
                      </template>
                    </el-radio-button>
                  </el-radio-group>
                </div>
              </el-col>
            </el-row>
          </el-col>
        </el-row>
      </div>
      <div class="table-box">
        <!-- grid -->
        <div class="grid-content" v-show="viewType === 'grid'">
          <div :class="['grid-item', { selected: isSelected(item) }]" v-for="(item, index) in srcList" :key="item.id">
            <el-image :src="item.file_url" style="max-width: 100%; max-height: 140px; cursor: pointer;"
                      :initial-index="index" @click="toggleSelection(item)"/>
            <div style="padding: 3px 6px; width: 100%">
              <el-tooltip
                  effect="dark"
                  :content="item.stored_name"
                  placement="top"
              >
                <div class="overflow-hidden whitespace-nowrap text-ellipsis">
                  {{ item.stored_name }}
                </div>
              </el-tooltip>
            </div>
            <div class="grid-item-title">
              <el-button type="primary" link @click.stop="handleDelImage(true, item)">删除</el-button>
              <el-popover :ref="(el: any) => popovers[index] = el" placement="top" :width="300" trigger="click"
                          @show="showRenamePopover(item)">
                <div style="display: flex; align-items: center; justify-content: center; gap: 5px;">
                  <el-input v-model="renameShow" size="small" style="" placeholder="图片名称"></el-input>
                  <el-button size="small" type="primary" link @click="closePopover(index)">取消</el-button>
                  <el-button size="small" type="primary" @click="handleReName(item, index)">
                    确定
                  </el-button>
                </div>
                <template #reference>
                  <el-button type="primary" link>重命名</el-button>
                </template>
              </el-popover>
              <el-button type="primary" link @click.stop="handlePreview(item.file_url)">查看</el-button>
            </div>
          </div>
        </div>
        <!-- table -->
        <el-table ref="tableRef" :data="srcList" style="width: 100%" @selection-change="toggleSelection"
                  v-show="viewType === 'table'">
          <el-table-column type="selection" v-if="multiple"></el-table-column>
          <el-table-column
              label=""
              width="50"
              v-else>
            <template #default="{ row }">
              <el-radio
                  :label="row.id"
                  v-model="selectedRowId"
                  @change="toggleSelection(row)">
              </el-radio>
            </template>
          </el-table-column>
          <el-table-column prop="id" label="图片">
            <template #default="scope">
              <el-image style="width: 68px; height: 68px;" :src="scope.row.file_url"></el-image>
            </template>
          </el-table-column>
          <el-table-column prop="stored_name" label="名称"/>
          <el-table-column label="操作">
            <template #default="scope">
              <el-button type="primary" link @click.stop="handleDelImage(true, scope.row)">删除</el-button>
              <el-popover :ref="(el: any) => popovers_table[scope.$index] = el" placement="top" :width="300" trigger="click"
                          @show="showRenamePopover(scope.row)">
                <div style="display: flex; align-items: center; justify-content: center; gap: 5px;">
                  <el-input v-model="renameShow" size="small" placeholder="图片名称"></el-input>
                  <el-button size="small" type="primary" link @click="closePopoverTable(scope.$index)">取消</el-button>
                  <el-button size="small" type="primary" @click="handleReName(scope.row, scope.$index)">
                    确定
                  </el-button>
                </div>
                <template #reference>
                  <el-button type="primary" link>重命名</el-button>
                </template>
              </el-popover>
              <el-button type="primary" link @click.stop="handlePreview(scope.row.file_url)">查看</el-button>
            </template>
          </el-table-column>
        </el-table>
        <!-- 分页组件 -->
        <div class="py-5 px-0 flex justify-end">
          <el-pagination v-model:current-page="currentPage" v-model:page-size="pageSize"
                         :page-sizes="[10, 20, 100, 200]" :size="size" :disabled="false" background
                         layout="total, sizes, prev, pager, next, jumper" :total="total" @size-change="handleSizeChange"
                         @current-change="handleCurrentChange"/>
        </div>
      </div>
    </el-col>
  </el-row>
  <!-- 添加/编辑分类 -->
  <el-dialog v-model="dialogFormVisible" :title="categoryTile" width="500">
    <el-form ref="formRef" :model="form" :rules="rules">
      <el-form-item label="分类名称" prop="cate_name">
        <el-input v-model="form.cate_name" autocomplete="off"/>
      </el-form-item>
    </el-form>
    <template #footer>
      <div class="dialog-footer">
        <el-button @click="close">取消</el-button>
        <el-button type="primary" @click="append">确定</el-button>
      </div>
    </template>
  </el-dialog>
  <!-- 移动图片至其他目录 -->
  <el-dialog v-model="dialogCidVisible" title="移至其他分类" width="500">
    <el-form ref="formCidRef" :model="file_cid">
      <el-form-item label="分类" prop="pid">
        <el-tree-select
            v-model="file_cid"
            :data="dataSource"
            :props="defaultProps"
            :render-after-expand="false"
            check-strictly
            value-key="id"/>
      </el-form-item>
    </el-form>
    <template #footer>
      <div class="dialog-footer">
        <el-button @click="dialogCidVisible = false">取消</el-button>
        <el-button type="primary" @click="handleMoveCate">确定</el-button>
      </div>
    </template>
  </el-dialog>
  <!-- 图片预览组件 -->
  <el-image-viewer v-if="previewVisible" :url-list="previewList" @close="previewVisible = false"/>
</template>

<script setup lang="ts">
import {ref, reactive, nextTick, onMounted, computed} from 'vue';
import {ElMessage, ElMessageBox} from 'element-plus'
import {Search, Grid, MoreFilled, CirclePlus} from '@element-plus/icons-vue'
import {useAuthStore} from "@/stores/auth";
import type {FormInstance, FormRules} from 'element-plus'
import type {ComponentSize} from 'element-plus'
import {
  getFileCateListApi,
  saveFileCateInfoApi,
  updateFileCateInfoApi,
  getFileCateInfoApi,
  deleteFileCateInfoApi,
} from '@/api/fileCate'
import {getFileListApi, deleteFileInfoApi, updateFileInfoApi, moveFileInfoApi} from '@/api/file'

// 定义组件属性
const props = defineProps({
  // 是否为dialog模式
  dialog: {
    type: Boolean,
    default: false,
  },
  // 是否多选
  multiple: {
    type: Boolean,
    default: true,
  },
});

// 定义emit事件
const emit = defineEmits(['useImage']);

// 定义 search 的类型接口
interface SearchParams {
  stored_name?: string; // 可选属性
}

// 初始化 search 对象，确保符合类型定义
const search = ref<SearchParams>({ stored_name: '' });
// 弹出层状态
const dialogFormVisible = ref(false);
const dialogCidVisible = ref(false);
// 搜索框状态
// 默认每页显示10条数据
const size = ref<ComponentSize>('default');
const currentPage = ref(1);
const pageSize = ref(10);
const total = ref(0);
// 跟踪选中的项目ID数组
const selectedItems = ref<number[]>([]);
// 预览状态
const previewVisible = ref(false);
const previewList = ref<string[]>([]);
// 对话框标题
const categoryTile = computed(() => (isAdd.value ? '新增分类' : '编辑分类'));
const isAdd = ref(false);
// 视图类型
const viewType = ref('grid')
// 单选模式下选中的row
const selectedRowId = ref(null)
const tableRef = ref(null)
// 重命名
const renameShow = ref('')
const popovers = ref([])
const popovers_table = ref([])
// 点击分类的id
const cateId = ref(null);
const file_cid = ref(null);
const fileType = ref('image');


interface Item {
  id: number;
  file_url: string;
  stored_name: string;
}

// 文件列表
const srcList = ref<Item[]>([]);

interface Tree {
  id: number
  label: string
  children?: Tree[]
}

// 配置项
const defaultProps = {
  value: 'id', // 选中值的字段
  label: 'cate_name', // 显示文本的字段
  children: 'children', // 子节点的字段
};

// 初始化分类
const initDataSource = [
  {cate_name: '全部', children: []}
];

// 顶级分类数据
const parentData = ref([
  {type: 'image', name: '图片'},
  {type: 'video', name: '视频'},
  {type: 'audio', name: '音频'},
  {type: 'document', name: '文档'},
]);

// 子级树形数据
const dataSource = ref<Tree[]>();

const formRef = ref<FormInstance>();

// 接口类型
interface FormDataTypes {
  pid: number
  cate_name: string,
  type: string
  id?: number
}

// 初始表单数据字段
const initForm = reactive<FormDataTypes>({
  pid: null,
  cate_name: '',
  type: null,
})

// 新增分类表单
const form = reactive({...initForm});

// 验证规则
const rules = ref<FormRules<FormDataTypes>>({
  pid: [
    {required: true, message: '请选择父级分类', trigger: 'change'},
  ],
  cate_name: [
    {required: true, message: '分类名称必填', trigger: 'change'},
  ]
});

// 触发renamePopover的show事件
const showRenamePopover = (item: any) => {
  renameShow.value = item.stored_name
}

// 手动关闭指定索引的 popover
const closePopover = (index: number) => {
  console.log(index)
  // 确保 index 在范围内
  if (popovers.value[index]) {
    // 触发指定的 popover 隐藏
    popovers.value[index].hide();
  }
};

const closePopoverTable = (index: number) => {
  console.log(index)
  // 确保 index 在范围内
  if (popovers_table.value[index]) {
    console.log(popovers_table.value)
    // 触发指定的 popover 隐藏
    popovers_table.value[index].hide();
  }
};

// 每页显示项目数量
const handleSizeChange = (val: number) => {
  console.log(`${val} items per page`)
}

// 点击页码
const handleCurrentChange = async (val: number) => {
  currentPage.value = val;
  await getFileList();
}

// 切换视图
const handleChangeView = (type: string) => {
  selectedItems.value = []
  viewType.value = type
  console.log(`切换视图：${type}`)
}

// 点击顶级分类
const handleClick = async () => {
  await getFileCateList();
}

// 点击左侧分类
const handleClickNode = async (data: any) => {
  cateId.value = data.id
  await getFileList();
}

// 新增|编辑弹出层
const addCategory = async (isNew: boolean, row?: { id: number }) => {
  dialogFormVisible.value = true;
  isAdd.value = isNew;

  // 清空表单和验证规则
  Object.assign(form, initForm);
  await nextTick(() => {
    formRef.value.clearValidate();
    formRef.value.resetFields();
  });

  form.pid = 0;
  form.type = fileType.value;

  // 子类新增
  if (isAdd.value && row) {
    form.pid = row.id
  }

  // false 是编辑
  if (!isAdd.value) {
    const response = await getFileCateInfoApi(row.id);
    Object.assign(form, response.data);
  }
}

// 选中文件
const toggleSelection = (item?: Item | Item[]) => {
  console.log(item)
  if (!props.multiple) { // 单选模式
    if (Array.isArray(item)) {
      return;
    } else if (item) {
      const index = selectedItems.value.findIndex(id => id === item.id);
      if (index > -1) {
        // 如果已经选中，则取消选中
        selectedItems.value.splice(index, 1);
      } else {
        // 如果未选中，则移除所有其他选中项，并添加新的选中项
        selectedItems.value = [item.id];
      }
    }
  } else { // 多选模式
    if (Array.isArray(item)) {
      // 如果传入的是一个数组，表示表格中的选中行
      selectedItems.value = item.map(row => row.id);
    } else if (item) {
      // 如果传入的是一个具体的 item 对象
      const index = selectedItems.value.findIndex(id => id === item.id);
      if (index > -1) {
        // 如果已经选中，则取消选中
        selectedItems.value.splice(index, 1);
      } else {
        // 如果未选中，则添加到选中列表
        selectedItems.value.push(item.id);
      }
    }
  }
}

// 是否选中图片
const isSelected = (item: Item): boolean => {
  return selectedItems.value.includes(item.id);
};

// 使用选中文件
const handleUseImage = () => {
  // 检查是否有文件被选中
  if (selectedItems.value.length > 0) {
    // 遍历所有被选中的文件
    const selectedUrls = selectedItems.value.map(selectedItem => {
      // 在所有文件中找到被选中的那个
      const item = srcList.value.find(item => item.id === selectedItem);
      // 返回选中文件的URL
      return item ? item.file_url : null;
    }).filter(file_url => file_url !== null); // 过滤掉未找到的文件

    // 如果找到了被选中的文件，触发 'useImage' 事件
    if (selectedUrls.length > 0) {
      // 根据是否为多选模式决定返回形式
      const result = props.multiple ? selectedUrls : selectedUrls[0];
      emit('useImage', result);
    }
  }
}

// 处理图片预览
const handlePreview = (url: string) => {
  previewList.value = [url];
  previewVisible.value = true;
}

// 新增分类
const append = async () => {
  if (!formRef.value) return;

  // 校验表单
  await formRef.value.validate();

  // 判断是否为新增或更新
  const isUpdate = !!form.id; // 如果存在 id，则为更新操作

  // 执行新增或更新操作
  if (isUpdate) {
    // 更新操作
    await updateFileCateInfoApi(form.id, form);
    ElMessage.success('更新成功');
  } else {
    // 新增操作
    await saveFileCateInfoApi(form);
    ElMessage.success('新增成功');
  }

  // 关闭对话框并刷新表格数据
  close();
  await getFileCateList();
}

// 移除分类
const remove = (row: Tree) => {
  ElMessageBox.confirm(
      '确定删除此数据吗?',
      '提示',
      {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning',
      }
  ).then(async () => {
    // 执行删除操作
    await deleteFileCateInfoApi(row.id);
    // 刷新表格数据
    await getFileCateList();
    // 提示删除成功
    ElMessage({
      type: 'success',
      message: '删除成功',
    });
  })
}

// 关闭分类表单弹出层
const close = () => {
  dialogFormVisible.value = false;
}

// 文件上传接口
const UploadUrl = computed(() => {
  return import.meta.env.VITE_API_BASE_URL + '/file_upload/upload';
});

const authStore = useAuthStore();

// 提前定义 getToken 函数
const getToken = () => {
  return authStore.token;
};

// 设置 header 头部
const header = reactive({
  Authorization: `Bearer ${getToken()}`
});

// 文件列表
const fileList = ref([]);

// 上传文件附带参数
const uploadData = computed(() => {
  return {
    cid: cateId.value,
  }
})

const beforeUpload = (file: any) => {
  // 最大文件大小(MB)
  const maxSizeMB = 10
  // 文件大小转换（MB → 字节）
  const maxSizeBytes = maxSizeMB * 1024 * 1024
  // 获取文件扩展名（小写）
  const fileExtension = file.name.split('.').pop().toLowerCase()
  console.log(fileExtension)

  // 允许的扩展名白名单
  const allowedExtensions = ['pdf', 'doc', 'docx', 'png', 'jpg', 'jpeg', 'txt']

  // 验证文件类型
  const isValidType = allowedExtensions.includes(fileExtension)

  if (!isValidType) {
    ElMessage.error(`仅支持上传以下格式：${allowedExtensions.join(', ')}`)
    return false // 阻止上传
  }

  // 验证文件大小
  if (file.size > maxSizeBytes) {
    ElMessage.error(`文件大小不能超过 ${maxSizeMB}MB（当前文件：${(file.size / 1024 / 1024).toFixed(2)}MB）`)
    return false
  }

  return true
}

// 文件上传成功时的钩子
const handleSuccess = async () => {
  ElMessage.success('文件上传成功');
  await getFileList();
};

// 文件上传失败时的钩子
const handleError = (err: any) => {
  console.log(err)
  ElMessage.error('文件上传失败:' + err.message);
};

// 删除图片事件
const handleDelImage = (isOne: boolean, item?: any) => {
  let ids = selectedItems.value;
  if (isOne) {
    ids = [item.id];
  }
  ElMessageBox.confirm(
      '确定要删除选中图片吗？',
      '提示',
      {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning',
      }
  ).then(async () => {
    await deleteFileInfoApi(ids);
    await getFileList();
    selectedItems.value = []
    ElMessage({
      type: 'success',
      message: '删除图片成功！',
    });
  })
}

// 获取分类列表
const getFileCateList = async () => {
  const response = await getFileCateListApi({type: fileType.value});
  dataSource.value = [...initDataSource, ...response.data];

  await getFileList();
}

// 获取文件列表
const getFileList = async () => {
  let params = {
    page: currentPage.value,
    page_size: pageSize.value,
    cid: cateId.value,
    type: fileType.value
  };
  const response = await getFileListApi({
    ...params,
    ...search.value,
  });
  srcList.value = response.data.list;
  total.value = response.data.total;
}

// 文件重命名事件
const handleReName = async (item: any, index: number) => {
  await updateFileInfoApi(item.id, {stored_name: renameShow.value})
  await getFileList();
  closePopover(index);
  closePopoverTable(index);
  ElMessage.success('更新成功');
}

// 移动至其他分类
const handleMoveCate = async () => {
  let data = {
    ids: selectedItems.value,
    cid: file_cid.value,
  }
  await moveFileInfoApi(data);
  await getFileList();
  selectedItems.value = [];
  dialogCidVisible.value = false;
  ElMessage.success('更新成功');
}

onMounted(() => {
  getFileCateList();
})
</script>

<style scoped>
.add-category {
  display: flex;
  align-items: center;
  justify-content: center;
  border-bottom: 1px solid var(--el-border-color);
  padding-bottom: 10px;
}

.el-form-item .el-form-item {
  margin-bottom: 18px !important;
}

.toolbar {
  padding: 0 20px;
}

.table-box {
  padding: 20px;
}

.grid-content {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 20px;
}

.grid-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: 146px;
  height: 146px;
  max-height: 146px;
  background-color: var(--el-bg-color);
  padding: 3px;
  position: relative;
  box-sizing: border-box;
  box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1),
  0 2px 4px -1px rgba(0, 0, 0, 0.06);
}

.grid-item.selected::before {
  content: '';
  position: absolute;
  top: -3px; /* 上移边框宽度 */
  left: -3px; /* 左移边框宽度 */
  right: -3px; /* 右移边框宽度 */
  bottom: -3px; /* 下移边框宽度 */
  border: 3px solid var(--el-color-primary);
  z-index: 1;
}

/* 确保内容位于伪元素之上 */
.grid-item > * {
  position: relative;
  z-index: 2;
}

.custom-tree-node {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 14px;
  padding-right: 8px;
}
</style>